#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/vmalloc.h>
#include <asm/uaccess.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("zhanglong");
#define MAX_COOKIE_LENGTH PAGE_SIZE

static struct proc_dir_entry *proc_entry;
static char *cookie_pot; // Space for procfile strings

ssize_t proc_write(struct file *filp, const char __user *buff,
        unsigned long len, void *data)
{
    return 1; //如果返回0, 写数据时不能返回
}

int proc_read(char *page, char **start, off_t off,
        int count, int *eof, void *data)
{
    int len = 0;
    unsigned long ttb = 0;
    struct vm_area_struct *vm = current->mm->mmap;

    memset(page, 0, MAX_COOKIE_LENGTH);
    //从c2读ttb
    __asm__ __volatile__ (
            "mrc p15, 0, %0, c2, c0, 0\n"
            :"=r" (ttb)
            );

    sprintf(page + len, "**********get the address information**********\n");
    len = strlen(page);
    sprintf(page + len, "current->comm: %s\n", current->comm); //执行当前进程的命令的名字
    len = strlen(page);
    sprintf(page + len, "current->state: %d\n", current->state); //运行状态
    len = strlen(page);
    sprintf(page + len, "currentr->mm = 0x%08x\n", current->mm);
    len = strlen(page);
    sprintf(page + len, "ttb = 0x%08x\n", ttb);
    len = strlen(page);
    sprintf(page + len, "currentr->mm->pgd = 0x%08x\n", current->mm->pgd); //页目录表的地址(好象与ttb相差0x90000000)
    len = strlen(page);
    sprintf(page + len, "**********the virtual memory area***************\n");
    len = strlen(page);
    sprintf(page + len, "vm_area: 0x%08x - 0x%08x\n", current->mm->mmap->vm_start, current->mm->mmap->vm_end); //
    len = strlen(page);

    vm = vm->vm_next;
    while((NULL != vm) && (vm != current->mm->mmap)){
        sprintf(page + len, "vm_area: 0x%08x - 0x%08x\n", vm->vm_start, vm->vm_end); //
        len = strlen(page);
        vm = vm->vm_next;
    };

    sprintf(page + len, "total_vm: 0x%x\t locked_vm: 0x%x\t shared_vm: 0x%x\t exec_vm: 0x%x\n",
            current->mm->total_vm, //进程地址空间的大小(页)
            current->mm->locked_vm, //锁住不能换出的页的个数
            current->mm->shared_vm, //共亨文件内存映射的页数
            current->mm->exec_vm); //可执行内存映射中的页数
    len = strlen(page);
    sprintf(page + len, "code: 0x%08x - 0x%08x\n",
            current->mm->start_code,
            current->mm->end_code); //代码

    len = strlen(page);
    sprintf(page + len, "data: 0x%08x - 0x%08x\n",
            current->mm->start_data,
            current->mm->end_data); //数据

    len = strlen(page);
    sprintf(page + len, "brk: 0x%08x - 0x%08x\n",
            current->mm->start_brk,
            current->mm->brk); //堆

    len = strlen(page);
    sprintf(page + len, "start_stack: 0x%08x\n", current->mm->start_stack); //用户堆栈的起始地址

    len = strlen(page);
    sprintf(page + len, "stack_vm: %d\n", current->mm->stack_vm); //用户态堆栈中的页数

    len = strlen(page);
    sprintf(page + len, "arg_area: 0x%08x - 0x%08x\n", current->mm->arg_start, current->mm->arg_end); //命令行参数的起始地址

    len = strlen(page);
    sprintf(page + len, "env_area: 0x%08x - 0x%08x\n", current->mm->env_start, current->mm->env_end); //环境变量的起始地址
    len = strlen(page);
    sprintf(page + len, "len = %d\n", len); //
    len = strlen(page);

    return len;
}

int init_proc_module(void)
{
    int ret = 0;
    cookie_pot = (char *)vmalloc(MAX_COOKIE_LENGTH);
    if (!cookie_pot)
    {
        ret = -ENOMEM;
    }
    else
    {
        memset(cookie_pot, 0, MAX_COOKIE_LENGTH);
        proc_entry = create_proc_entry("procfile", 0644, NULL);
        if (proc_entry == NULL)
        {
            ret = -ENOMEM;
            vfree(cookie_pot);
            printk(KERN_INFO "proc: Couldn't create proc entry\n");
        }
        else
        {
            proc_entry->read_proc = proc_read;
            proc_entry->write_proc = proc_write;
            //proc_entry->owner = THIS_MODULE;

            printk(KERN_INFO "proc: Module loaded.\n");
        }
    }
    return ret;
}
void cleanup_proc_module(void)
{
    remove_proc_entry("proc", NULL);
    vfree(cookie_pot);
    printk(KERN_INFO "proc: Module unloaded.\n");
}
module_init(init_proc_module);
module_exit(cleanup_proc_module);


